package top.v5it.logback.push.channel.dingtalk;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.lang.Assert;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.HmacAlgorithm;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.function.Consumer;

/**
 * 钉钉webhook请求工具
 *
 * @author zhanpu
 * @date 2021/7/25
 */
@Slf4j
public class DingTalkUtil {

    /**
     * 默认请求服务超时时间
     */
    private static final int DEFAULT_TIMEOUT = 15 * 1000;

    private DingTalkUtil() {
        throw new UnsupportedOperationException();
    }

    /**
     * 向钉钉群发送消息
     *
     * @param url     群消息地址
     * @param secret  密钥
     * @param request 请求参数
     * @param timeout 超时时间
     * @return {@link DingTalkRobotSendResponse}
     */
    public static DingTalkRobotSendResponse send(String url, String secret, DingTalkRobotSendRequest request, int timeout) {
        Assert.notBlank(url, "发送钉钉消息，服务地址不能为空");
        Assert.notNull(request, "发送钉钉消息，请求参数不能为空");
        final String jsonStr = JSONUtil.toJsonStr(request);
        return send(url, secret, jsonStr, timeout);
    }

    /**
     * 向钉钉群发送消息
     *
     * @param url     群消息地址
     * @param secret  密钥
     * @param jsonStr 请求参数
     * @param timeout 超时时间
     * @return {@link DingTalkRobotSendResponse}
     */
    public static DingTalkRobotSendResponse send(String url, String secret, String jsonStr, int timeout) {
        Assert.notBlank(url, "发送钉钉消息，服务地址不能为空");
        Assert.notBlank(jsonStr, "发送钉钉消息，请求参数不能为空");
        url += queryParams(secret);
        log.trace(">>>>>\n请求地址：{}\n请求参数：{}\n", url, jsonStr);
        String result = HttpUtil.post(url, jsonStr, (timeout == 0 ? DEFAULT_TIMEOUT : timeout));
        log.trace(">>>>>返回结果：{}", result);
        final DingTalkRobotSendResponse response = JSONUtil.toBean(result, DingTalkRobotSendResponse.class);
        if (response.getErrcode().compareTo(0) == 0) return response;
        log.error(result);
        throw new IllegalArgumentException(response.getErrmsg());
    }

    public static void asyncSend(String url, String secret, DingTalkRobotSendRequest request, int timeout, Consumer<HttpResponse> consumer) {
        Assert.notBlank(url, "发送钉钉消息，服务地址不能为空");
        Assert.notNull(request, "发送钉钉消息，请求参数不能为空");
        final String jsonStr = JSONUtil.toJsonStr(request);
        asyncSend(url, secret, jsonStr, timeout, consumer);
    }

    public static void asyncSend(String url, String secret, String jsonStr, int timeout, Consumer<HttpResponse> consumer) {
        Assert.notBlank(url, "发送钉钉消息，服务地址不能为空");
        Assert.notBlank(jsonStr, "发送钉钉消息，请求参数不能为空");
        url += queryParams(secret);
        log.trace(">>>>>\n请求地址：{}\n请求参数：{}\n", url, jsonStr);
        HttpRequest.post(url)
                .timeout((timeout == 0 ? DEFAULT_TIMEOUT : timeout))
                .body(jsonStr)
                .then(consumer);
    }

    /**
     * url参数
     *
     * @param secret 密钥
     * @return url参数
     */
    private static String queryParams(final String secret) {
        final long timestamp = System.currentTimeMillis();
        final String string2Str = timestamp + "\n" + secret;
        // 签名
        final String sign = Base64.encode(SecureUtil.hmac(HmacAlgorithm.HmacSHA256, secret).digest(string2Str));
        return "&timestamp=" + timestamp + "&sign=" + sign;
    }
}
